"""
Copyright 2012 Wieser Dietmar, Margit Mutschlechner.

This file is part of Multimedia Social Networking Platform.

Multimedia Social Networking Platform is free software: 
you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Multimedia Social Networking Platform is distributed
in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Multimedia Social Networking Platform.  
If not, see <http://www.gnu.org/licenses/>.

"""

from PyQt4 import QtGui, QtCore
from msnp.gui import UIText, Resources, MyStyle, GUIHelper, MySignal
from msnp import gui
from msnp.service.network import NetworkController, LeaveRequest
from msnp.service.network.model import Model
from msnp.service.synch import LocalSynchController
from msnp.model import PTPModel
from msnp.persistence import XMLController
from msnp.logger import Logger
from msnp.service import network

class GroupCollectionWidget(QtGui.QMainWindow):
    """This class represents a group collection widget which represents the main widget of the application
    where, among others, the groups of the user are displayed.
    
    Parameters:
        __parent: A QWidget object containing the parent frame. Default None.
        __synchPossible: A boolean value, True if synchronization towards the media player is enables, False otherwise.
        __dock: A QDockWidget object containing the item __contentWidget.
        __contentWidget: A GroupCollectionContentWidget object.
        __menuBar: A QMenuBar object containing the items __menuMain and __menuExit.
        __menuMain: A menu entry of the item __menubar containing actions for opening a GroupWidget to search a group or to create a group,
                    to open the ConfirmWidget, to synchronize towards the media player,
                    open a widget to display the entries of the media database and to open a SettingsWidget.
        __menuExit: A menu entry of the item __menubar containing an action to close the application and to logout.
    """
    def __init__(self, groups, parent=None):
        """The init-method."""
        QtGui.QWidget.__init__(self, parent)
        self.__synchPossible = True
        self.setWindowTitle(UIText.TITLE_GROUP_COLLECTION)
        self.setWindowIcon(QtGui.QIcon(Resources.IMAGE_GROUP_ICON))
        self.setFixedSize(400, 600)
        GUIHelper.centerWidget(self)
        self.__build(groups)
        MySignal.emitLogoutEnabledSignal(True)
        
    def __build(self, groups): 
        """Initializes the widget and adds its contained items."""
        self.__initMenus()
        self.__initDockWidget(groups)
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.__dock)
        self.connect(self, QtCore.SIGNAL("triggered()"), self.closeEvent)
        
    def __initDockWidget(self, groups):
        """Initializes the item __dock and adds its contained items."""
        self.__dock = QtGui.QDockWidget(self)
        self.__dock.setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures)
        self.__dock.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
        self.__contentWidget = GroupCollectionContentWidget(groups, self.__dock, self)
        self.__dock.setWidget(self.__contentWidget)
            
    def __initMenus(self):
        """Initializes the item __menuBar and adds its contained items."""
        self.__menuBar = self.menuBar()
        self.__menuMain = self.__menuBar.addMenu(UIText.LABEL_MENU)
        self.__menuExit = self.__menuBar.addMenu(UIText.LABEL_EXIT)
        self.__initActionsForMenuMain()
        self.__initActionsForMenuExit()
        
    def __initActionsForMenuMain(self):
        """Initializes the item __menuMain and its actions."""
        #settings
        settingsAction = QtGui.QAction(QtGui.QIcon(Resources.IMAGE_SETTINGS), UIText.LABEL_SETTINGS, self)
        settingsAction.setShortcut(UIText.SC_SETTINGS)
        settingsAction.setStatusTip(UIText.LABEL_SETTINGS_TIP)
        self.connect(settingsAction, QtCore.SIGNAL('triggered()'), self.__openSettings)
        
        #group search
        searchAction = QtGui.QAction(QtGui.QIcon(Resources.IMAGE_SEARCH_ICON), UIText.LABEL_GROUP_SEARCH, self)
        searchAction.setShortcut(UIText.SC_GROUP_SEARCH)
        searchAction.setStatusTip(UIText.LABEL_GROUP_SEARCH_TIP)
        self.connect(searchAction, QtCore.SIGNAL('triggered()'), self.__openGroupWidget)
        
        #synchronize
        synchronizeAction = QtGui.QAction(QtGui.QIcon(Resources.IMAGE_SYNCHRONIZE_ICON), UIText.LABEL_SYNCHRONIZE, self)
        synchronizeAction.setShortcut(UIText.SC_SYNCHRONIZE)
        synchronizeAction.setStatusTip(UIText.LABEL_SYNCHRONIZE_TIP)
        self.connect(synchronizeAction, QtCore.SIGNAL('triggered()'), self.synchronizePlayerDB)
        
        #view database
        databaseAction = QtGui.QAction(QtGui.QIcon(Resources.IMAGE_AUDIO_LIST_ICON), UIText.LABEL_SHOW_DATABASE, self)
        databaseAction.setShortcut(UIText.SC_SHOW_DATABASE)
        databaseAction.setStatusTip(UIText.LABEL_SHOW_DATABASE_TIP)
        self.connect(databaseAction, QtCore.SIGNAL('triggered()'), self.__showDatabase)
        
        #new group
        newGroupAction = QtGui.QAction(QtGui.QIcon(Resources.IMAGE_NEW_GROUP), UIText.LABEL_CREATE_GROUP, self)
        newGroupAction.setShortcut(UIText.SC_CREATE_GROUP)
        newGroupAction.setStatusTip(UIText.LABEL_CREATE_GROUP_TIP)
        self.connect(newGroupAction, QtCore.SIGNAL('triggered()'), self.__createNewGroup)
        
        #confirm members
        confirmMembersAction = QtGui.QAction(QtGui.QIcon(Resources.IMAGE_CONFIRM_MEMBERS), UIText.LABEL_CONFIRM_MEMBERS, self)
        confirmMembersAction.setShortcut(UIText.SC_CONFIRM_MEMBER)
        confirmMembersAction.setStatusTip(UIText.LABEL_CONFIRM_MEMBERS_TIP)
        self.connect(confirmMembersAction, QtCore.SIGNAL('triggered()'), self.__confirmMembers)
        
        #add actions to menumain
        self.__menuMain.addAction(searchAction)
        self.__menuMain.addAction(newGroupAction)
        self.__menuMain.addAction(confirmMembersAction)
        self.__menuMain.addAction(synchronizeAction)
        self.__menuMain.addAction(databaseAction)
        self.__menuMain.addAction(settingsAction)
        
    def __initActionsForMenuExit(self):
        """Initializes the item __menuExit and its actions."""
        logoutAction = QtGui.QAction(QtGui.QIcon(Resources.IMAGE_LOGOUT), UIText.LABEL_LOGOUT, self)
        logoutAction.setShortcut(UIText.SC_LOGOUT)
        logoutAction.setStatusTip(UIText.LABEL_LOGOUT)
        self.connect(logoutAction, QtCore.SIGNAL('triggered()'), self.__logout)
        self.__menuExit.addAction(logoutAction)
        
        closeAction = QtGui.QAction(QtGui.QIcon(Resources.IMAGE_EXIT), UIText.LABEL_CLOSE, self)        
        closeAction.setShortcut(UIText.SC_QUIT)
        closeAction.setStatusTip(UIText.LABEL_CLOSE_APP_TIP)
        self.connect(closeAction, QtCore.SIGNAL('triggered()'), self.__close)
        self.__menuExit.addAction(closeAction)
        
    def enableSynchronization(self, enable=True):
        """This method is called from outside when synchronization status changes from possible to impossible or vice versa."""
        self.__synchPossible = enable
        self.__contentWidget.enablePlayerSynchButton(enable)
        
    def refreshGroupList(self, newGroup, remove):
        """This method is called when the content of the item __contentWidget changes."""
        if self.__contentWidget != None:
            self.__contentWidget.refreshGroupList(newGroup, remove)
    
    def refreshBtnMessages(self):
        """This method is called when the text on the message button of the item __contentWidget changes."""
        if self.__contentWidget != None:
            self.__contentWidget.refreshBtnMessages()
        
    def __openSettings(self):
        """This method is connected to an action of the item __menuMain and opens a SettingsWidget object."""
        gui.GUIController.openSettings(self, self.__synchPossible)
        
    def __showDatabase(self):
        """This method is connected to an action of the item __menuMain and opens an AudioWidget object."""
        settings = XMLController.readAllSettings()
        mediaDBSettings = settings.getCurrentUserSettings().getMediaDatabaseSettings()
        if mediaDBSettings.isComplete(): 
            gui.GUIController.openAudioList(self)
            LocalSynchController.readAllStoredAudios()
        else:
            QtGui.QMessageBox.information(self, UIText.MSG_ATTENTION, UIText.MSG_COMPLETE_MEDIA_DB_SETTINGS, UIText.BUT_OK)
        
    def __openGroupWidget(self):
        """This method is connected to an action of the item __menuMain and opens a GroupWidget object to search for groups."""
        gui.GUIController.openGroupWidget(self)
        
    def __createNewGroup(self):
        """This method is connected to an action of the item __menuMain and opens a GroupWidget object to create a new group."""
        mediaDBSettings = XMLController.readAllSettings().getCurrentUserSettings().getMediaDatabaseSettings()
        if mediaDBSettings.isComplete():
            gui.GUIController.openGroupWidget(self, False, GUIHelper.GroupDetailType.NEW_GROUP)
        else:
            QtGui.QMessageBox.information(self, UIText.MSG_ATTENTION, UIText.MSG_GROUP_CREATE_FAILED_MEDIA_DB, UIText.BUT_OK)
    
    def __confirmMembers(self):
        """This method is connected to an action of the item __menuMain and opens a ConfirmWidget object."""
        gui.GUIController.openConfirmWidget()
        network.NetworkController.getGroupsWithMembersToConfirm()
    
    def synchronizePlayerDB(self):
        """This method is connected to an action of the item __menuMain and starts the synchronization procedure towards the media player."""
        if (self.__synchPossible):
            reply = QtGui.QMessageBox.question(self, UIText.MSG_ATTENTION, UIText.MSG_PLAYER_SYNCH_REALLY, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
            if reply == QtGui.QMessageBox.Yes:
                settings = XMLController.readAllSettings()
                playerDB = settings.getCurrentUserSettings().getPlayerDatabaseSettings()
                mediaDB = settings.getCurrentUserSettings().getMediaDatabaseSettings()
                if playerDB.isComplete() and mediaDB.isComplete():
                    MySignal.emitSynchEnableSignal(False, True, PTPModel.ReturnType.SUCCESSFUL)
                    LocalSynchController.synchWithPlayer()
                else:
                    QtGui.QMessageBox.information(self, UIText.MSG_ATTENTION, UIText.MSG_COMPLETE_SYNCH_DB_SETTINGS, UIText.BUT_OK)
        else:
            QtGui.QMessageBox.information(self, UIText.MSG_ATTENTION, UIText.MSG_PLAYER_SYNCH_PENDING, UIText.BUT_OK)
    
    def openMessages(self):
        """This method is called by a button of the item __contentWidget and opens a MessageWidget object."""
        gui.GUIController.openMessageWidget(self)
    
    def showSynchFinishedDialog(self):
        """This method is called from outside and opens a QMessageBox to inform about the finished synchronization process from the media database towards the media player."""
        QtGui.QMessageBox.information(self, UIText.LABEL_FINISHED, UIText.MSG_MEDIA_SYNCH_FINISHED, UIText.BUT_OK)
        
    def showRestartPlayerDialog(self):
        """This method is called from outside and opens a QMessageBox to inform about the restart of the media player."""
        QtGui.QMessageBox.information(self, UIText.LABEL_FINISHED, UIText.MSG_RESTART_PLAYER, UIText.BUT_OK)
        
    def showNothingToSynchDialog(self):
        """This method is called from outside and opens a QMessageBox to inform that there is no data to synchronize."""
        QtGui.QMessageBox.information(self, UIText.LABEL_FINISHED, UIText.MSG_NOTHING_TO_SYNCH, UIText.BUT_OK)
        
    def showImportPlayerDataFinishedDialog(self):
        """This method is called from outside and opens a QMessageBox to inform about the finished synchronization process from the media player towards the media database."""
        QtGui.QMessageBox.information(self, UIText.LABEL_FINISHED, UIText.MSG_IMPORT_PLAYER_DATA_FINISHED, UIText.BUT_OK)
        
    def showErrorDialog(self, errorMsg):
        """This method is called from outside and opens a QMessageBox to inform about an error."""
        QtGui.QMessageBox.information(self, UIText.MSG_ATTENTION, errorMsg, UIText.BUT_OK)
        
    def showPlayerDBNotSetDialog(self):
        """This method is called from outside and opens a QMessageBox to inform that the player database credentials are not set."""
        QtGui.QMessageBox.information(self, UIText.MSG_ATTENTION, UIText.MSG_PLAYER_DB_NOT_SET_INFO, UIText.BUT_OK)
        
    def processPlayerDatabaseErrorDialog(self, type):
        """This method is called from outside and opens a QMessageBox to inform about an error happened in the player database."""
        QtGui.QMessageBox.information(self, UIText.MSG_ATTENTION, UIText.MSG_DB_EXCEPTION_PLAYERDB + type, UIText.BUT_OK)
        
    def processMediaDatabaseErrorDialog(self, type):
        """This method is called from outside and opens a QMessageBox to inform about an error happened in the media database."""
        QtGui.QMessageBox.information(self, UIText.MSG_ATTENTION, UIText.MSG_DB_EXCEPTION_MEDIADB + type, UIText.BUT_OK)
        
    def processPTPDatabaseErrorDialog(self, type):
        """This method is called from outside and opens a QMessageBox to inform about an error happened in the network database."""
        QtGui.QMessageBox.information(self, UIText.MSG_ATTENTION, UIText.MSG_DB_EXCEPTION_PTPDB + type, UIText.BUT_OK)
        settings = XMLController.readAllSettings()
        Logger.info("Try to delete msnp database settings.")
        settings.getCurrentUserSettings().getMSNPDatabaseSettings().deleteDBSettings()
        XMLController.storeSettings(settings)
        LeaveRequest.requestFinish(True)
        
    def __close(self):
        """This method is called by an action of the item __menuExit and sets all widgets to invisible."""
        gui.GUIController.setWidgetsVisible(False)
        
    def __logout(self):
        """This method is called by an action of the item __menuExit and logs the user out."""
#        gui.MySignal.emitLogoutSignal()
        LeaveRequest.requestFinish(False)
        
    def closeEvent(self, event):
        """This method is called when the user closes the widget. Calls the method __close() and ignores the event."""
        self.__close()
        event.ignore()
        
        
class GroupCollectionContentWidget(QtGui.QWidget):
    """This class represents a group collection content widget, an item of the GroupCollectionWidget where the groups itself are displayed.
    
    Parameters:
        __parent: A QWidget object containing the parent frame. Default None.
        __parentDockWidget: A QWidget containing the GroupCollectionWidget where this item is added to.
        __mainLayout: A QVBoxLayout object containing the items __titleLabel, __list and __btnWidget.
        __groups: A list of Group objects to be displayed.
        __msgCount: An integer value counting the number of messages the user received.
        __titleLabel: A QLabel object.
        __list: A GroupListWidget object.
        __btnWidget: A QWidget object containing the items __butSynch and __butMsgs.
        __butSynch: A QPushButton object connected to the method __synchronizePlayerDB().
        __butMsgs: A QPushButton object connected to the method __openMessages().
    """
    def __init__(self, groups, parentDock=None, parent=None):
        """The init-method."""
        QtGui.QWidget.__init__(self, parentDock)
        self.__parentDockWidget = parentDock
        self.__parent = parent
        self.__groups = groups
        self.__msgCount = 0
        self.__build()
        
    def __build(self):
        """Initializes the item __mainLayout and adds its contained items."""
        self.__cleanLayout()
        self.__initLabels()
        self.__initListWidget()
        self.__initButtons()
        self.__initButtonWidget()
        self.__mainLayout.addWidget(self.__titleLabel)
        self.__mainLayout.addWidget(self.__list)
        self.__mainLayout.addWidget(self.__btnwidget)
        
    def __initLabels(self):
        """Initializes the item __titleLabel."""
        self.__titleLabel = QtGui.QLabel(UIText.LABEL_MY_GROUPS)
        self.__titleLabel.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignTop)
        self.__titleLabel.setFont(MyStyle.getFont18Bold())
        self.__titleLabel.setTextFormat(QtCore.Qt.RichText)
        
    def __initListWidget(self):
        """Initializes the item __list and adds its contained items."""
        self.__list = GroupListWidget(self.__parent, self.__parentDockWidget)
        if self.__groups != None and len(self.__groups) > 0:
            for group in self.__groups:
                self.__list.addGroupItem(group)
        else:
            self.__list.addListEmptyItem()
            
    def __initButtonWidget(self):
        """Initializes the item __btnWidget and adds its contained items."""
        self.__btnwidget = QtGui.QWidget()
        layout = QtGui.QHBoxLayout()
        layout.addWidget(self.__butSynch)
        layout.addWidget(self.__butMsgs)
        self.__btnwidget.setLayout(layout)
            
    def __initButtons(self):
        """Initializes the items __butSynch and __butMsgs."""
        self.__butSynch = QtGui.QPushButton(UIText.BUT_SYNCHRONIZE, self)
        self.__butSynch.setFocusPolicy(QtCore.Qt.NoFocus)
        self.__butSynch.setIcon(QtGui.QIcon(Resources.IMAGE_SYNCHRONIZE_ICON))
        if self.__msgCount == 0:
            self.__butMsgs = QtGui.QPushButton(UIText.BUT_NO_NEW_MESSAGES, self) 
            self.__butMsgs.setEnabled(False)
        else:
            self.__butMsgs = QtGui.QPushButton(UIText.BUT_NEW_MESSAGES % self.__msgCount, self) 
            self.__butMsgs.setEnabled(True)
        self.__butMsgs.setFocusPolicy(QtCore.Qt.NoFocus)
        self.__butMsgs.setIcon(QtGui.QIcon(Resources.IMAGE_MESSAGE))
        #register handler
        self.connect(self.__butSynch, QtCore.SIGNAL('clicked()'), self.__synchronizePlayerDB)
        self.connect(self.__butMsgs, QtCore.SIGNAL('clicked()'), self.__openMessages)
        
    def __cleanLayout(self):
        """Removes all items from the item __mainLayout."""
        import sip
        if self.layout() != None:
            oldLayout = self.layout()
            for i in reversed(range(oldLayout.count())):
                oldLayout.itemAt(i).widget().setParent(None)
            sip.delete(oldLayout)
        self.__mainLayout = QtGui.QVBoxLayout()
        self.setLayout(self.__mainLayout)
        
    def enablePlayerSynchButton(self, enable):
        """Sets the item __butSynch to enabled or disabled, depending on the given value."""
        self.__butSynch.setEnabled(enable)
        
    def __synchronizePlayerDB(self):
        """This method is connected to the item __butSynch and calls the method synchronizePlayerDB() of the parent."""
        self.__parent.synchronizePlayerDB()
#        gui.GUIController.openPersonalMessageWidget('delago')
        
    def __openMessages(self):
        """This method is connected to the item __butMsgs and calls the method openMessages() of the parent."""
        self.__msgCount = 0
        self.__butMsgs.setEnabled(False)
        self.__butMsgs.setText(UIText.BUT_NO_NEW_MESSAGES)
        self.__parent.openMessages()
        
    def refreshGroupList(self, newGroup, remove):
        """This method is called by the parent. It removes or adds the given group from the list __groups and refreshes the whole widget."""
        if remove:
            for group in self.__groups:
                if group.getGroupname() == newGroup.getGroupname() and group.getOwnername() == newGroup.getOwnername():
                    self.__groups.remove(group)
                    break
        else:
            self.__groups.append(newGroup)
        self.__build()
    
    def refreshBtnMessages(self):
        """This method is called by the parent. It refreshes the text on the item __butMsgs."""
        if self.__msgCount >= 0:
            self.__butMsgs.setEnabled(True)
        self.__msgCount += 1
        self.__butMsgs.setText(UIText.BUT_NEW_MESSAGES % self.__msgCount)
        Logger.info("set btnmsg count to " + str(self.__msgCount))
        
class GroupListWidget(QtGui.QListWidget):
    """This class represents a group list widget, an item of the GroupCollectionContentWidget which displays the groups of the user.
    
    Parameters:
        __parent: A QWidget object containing the parent frame. Default None.
        __parentDock: A QWidget containing the GroupCollectionWidget where this item is added to.
        __groups: A list of Group objects to be displayed.
        __reactOnDoubleClick: A boolean value, True if a double click should be executed, False otherwise.
    """
    def __init__(self, parent, parentDock=None):
        """The init-method."""
        QtGui.QListWidget.__init__(self, parentDock)
        self.__reactOnDoubleClick = True
        self.__parent = parent
        self.__groups = []
        self.connect(self, QtCore.SIGNAL("itemDoubleClicked(QListWidgetItem*)"), self.__doubleClick)
        
    def addGroupItem(self, group):
        """Appends the given group to the list __groups, creates a new QListWidgetItem and adds it to the widget."""
        item = QtGui.QListWidgetItem()
        item.setIcon(QtGui.QIcon(Resources.IMAGE_GROUP_ICON))
        item.setText(group.getGroupname() + " (" + group.getOwnername() + ")")
        item.setTextAlignment(QtCore.Qt.AlignLeft)
        item.setFont(MyStyle.getFont13())
        self.addItem(item)
        self.__groups.append(group)
        
    def addListEmptyItem(self):
        """Creates a new void QListWidgetItem and adds it to the widget. Sets __reactOnDoubleClick to False."""
        self.__reactOnDoubleClick = False
        item = QtGui.QListWidgetItem()
        item.setText(UIText.LABEL_NO_GROUP)
        item.setTextAlignment(QtCore.Qt.AlignCenter)
        item.setFont(MyStyle.getFont13())
        self.addItem(item)
    
    def __doubleClick(self):
        """This method is connected to the widget. Only if the boolean item __reactOnDoubleClick is True the method's body is executed,
        which starts a group search procedure for the double-clicked entry."""
        if self.__reactOnDoubleClick:
            gui.GUIController.openGroupWidget(self.__parent, False, None)
            selectedItem = self.selectedIndexes()[0].row()
            ownername = self.__groups[selectedItem].getOwnername()
            groupname = self.__groups[selectedItem].getGroupname()
            NetworkController.getGroups(ownername, groupname, None, None, Model.CallbackReactType.DISPLAYGROUPDETAILS)
